/*
 *  Copyright 2011 Arngrimur Bjarnason 
 *  
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
 
 

/*
Copyright 2012 Arngrimmur Bjarnason

   Licensed under the Apache License, Version 2.0 (the "License");
   you may not use this file except in compliance with the License.
   You may obtain a copy of the License at

       http://www.apache.org/licenses/LICENSE-2.0

   Unless required by applicable law or agreed to in writing, software
   distributed under the License is distributed on an "AS IS" BASIS,
   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
   See the License for the specific language governing permissions and
   limitations under the License.
*/

/**
 * 
 */
package org.arngrimur.deviationtable.db;

import java.util.ArrayList;
import java.util.Collection;
import java.util.SortedSet;
import java.util.TreeSet;

import org.arngrimur.deviationtable.IDegree;
import org.arngrimur.deviationtable.compass.Compass;
import org.arngrimur.deviationtable.degree.AbstractDegree;
import org.arngrimur.deviationtable.degree.ReferenceDegree;
import org.arngrimur.deviationtable.view.ReferenceDisplayString;


import android.content.Context;
import android.database.Cursor;

/**
 * @author Arngrimur Bjarnason, arngrimurbjarnason@gmail.com
 *
 */
public class DataModel {
	private Compass referenceCompass = new Compass(DatabaseConnector.REF_TABLE);
	private SortedSet<ReferenceDegree> referenceValues = new TreeSet<ReferenceDegree>();
	private Collection<Compass> compasses = new ArrayList<Compass>();
	private DatabaseConnector database = null;
	
	public DataModel(Context context) {
		this.database = new DatabaseConnector(context);
		this.database.readMappedValues(this.referenceValues,
				this.compasses, this);
	}
	
	public Compass getReferenceCompass() {
		return this.referenceCompass;
	}
	
	/**
	 * @return
	 */
	public Collection<Compass> getCompasses() {
		return this.compasses;
	}
	/**
	 * @param degree
	 */
	public void removeReferenceValue(IDegree degree) {
		this.referenceValues.remove(degree);
		for(Compass c : compasses) {
			c.removeReadValue(degree);		
		}
		//TODO delete reference from data base
	}
	/**
	 * @param reference
	 */
	public void addReferenceValue(ReferenceDisplayString reference) {
		ReferenceDegree degree = (ReferenceDegree) reference.getDegree();
		this.referenceValues.add(degree);
		String insertStatement = "INSERT INTO "
				+ DatabaseConnector.REF_TABLE + "("
				+ DatabaseConnector.DEGREE + ") VALUES ( "
				+ degree.getValue().toString() + ")";
		database.executeSql(insertStatement);
	}
	/**
	 * @return
	 */
	public Collection<ReferenceDegree> getRefenceValues() {
		return this.referenceValues;
	}
	/**
	 * @param compass
	 */
	public void addCompass(Compass compass) {
		this.compasses.add(compass);
		String createStatement = "CREATE TABLE IF NOT EXISTS "
				+ compass.getDbName() + "( " + DatabaseConnector.ID
				+ " INTEGER PRIMARY KEY, " + DatabaseConnector.REF_ID
				+ " INTEGER REFERENCES " + DatabaseConnector.REF_TABLE
				+ "(" + DatabaseConnector.ID + ") ON UPDATE CASCADE, "
				+ DatabaseConnector.DEGREE
				+ " INTEGER UNIQUE ON CONFLICT IGNORE)";
		this.database.executeSql(createStatement);
	}
	
	/**
	 * Gets the reference value from the reference set
	 * 
	 * @param reference
	 *            String values of reference
	 * @return The Degree with the value of reference or null if not found
	 */
	 public IDegree getReferenceValue(String reference) {
		AbstractDegree found = null;
		Double ref = new Double(reference);
		for (AbstractDegree d : this.referenceValues) {
			if (d.getDegree().compareTo(ref) == 0) {
				found = d;
				break;
			}
		}
		return found;
	}
	

	/**
	 * @param compassName
	 * @return
	 */
	public Compass getCompassFromName(String compassName) {
		for(Compass c  : compasses) {
			if(c.getName().equals(compassName)) {
				return c;
			}
		}
		throw new IllegalArgumentException("No such compass: "+compassName);
	}

	/**
	 * Deletes the compass at index {@code index}
	 * @param index Index of compass
	 */
	public void deleteCompass(int index) {
		Compass compass = ((ArrayList<Compass>)this.compasses).remove(index);
		String deleteStatement = "DROP TABLE " + compass.getDbName();
		this.database.executeSql(deleteStatement);
	}	

	/**
	 * Inserts data for a given compass
	 * 
	 * @param degree
	 *            The degree
	 * @param reference
	 *            The reference values
	 * @param compass
	 *            The compass for which the degree has been read from
	 */
	public void insertIntoDatabase(IDegree degree, String reference,
			Compass compass) {
		// Get the foreign key for this entry
		Cursor cursor = this.database
				.executeQuery(DatabaseConnector.REF_TABLE,
						new String[] { DatabaseConnector.ID },
						DatabaseConnector.DEGREE
								+ "= "
								+ this.getReferenceValue(reference)
										.getDegree().toString(), null, null,
						null, null);

		cursor.moveToFirst();
		int foreignKey = cursor.getInt(0);

		// Check if it exist already in database then update
		// else create entry in db.
		cursor = this.database.executeQuery(compass.getDbName(),
				new String[] { DatabaseConnector.REF_ID },
				DatabaseConnector.REF_ID + "=" + foreignKey, null, null, null,
				null);
		if (cursor.getCount() == 1) {
			String updateStatement = "UPDATE " + compass.getDbName() + " SET "
					+ DatabaseConnector.DEGREE + "="
					+ degree.getDegree().toString() + "WHERE "
					+ DatabaseConnector.REF_ID + "=" + foreignKey;
			this.database.executeSql(updateStatement);
		} else {
			String insertStatement = "INSERT INTO " + compass.getDbName()
					+ "( " + DatabaseConnector.REF_ID + ", "
					+ DatabaseConnector.DEGREE + " ) VALUES ( " + foreignKey
					+ ", " + degree.getDegree().toString() + " )";
			this.database.executeSql(insertStatement);
		}
	}
}
